home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 7
/
Amiga Format AFCD07 (Dec 1996, Issue 91).iso
/
serious
/
shareware
/
comms
/
internet
/
html-related
/
hsc
/
source
/
hsclib
/
eval.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-08-17
|
38KB
|
1,469 lines
/*
* hsclib/eval.c
*
* attribute value evaluation functions
*
* Copyright (C) 1995,96 Thomas Aglassinger
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* updated: 17-Aug-1995
* created: 11-Oct-1995
*/
#define NOEXTERN_HSCLIB_EVAL_H
#include <ctype.h>
#include <time.h>
#include "hsclib/inc_base.h"
#include "hsclib/eval.h"
#include "hsclib/input.h"
#include "hsclib/skip.h"
#include "hsclib/uri.h"
/* maximul length of an operator identifer */
#define MAX_OP_LEN 8
/* unknown operator */
#define OP_NONE 0
/* step-size for temp. string */
#define TMP_STEPSIZE 128
/*
* equation operators
*/
#define OP_EQ_STR "="
#define OP_NEQ_STR "<>"
#define OP_GT_STR ">"
#define OP_LT_STR "<"
#define OP_GTE_STR ">="
#define OP_LTE_STR "<="
#define OP_CEQ_STR "==" /* TODO: case sensitive string comparison */
#define OP_INSIDE_STR "IN" /* TODO: check for substring */
#define OP_CL_BRAKET_STR ")" /* closing braket */
#define OP_EQ 1
#define OP_NEQ 2
#define OP_GT 3
#define OP_LT 4
#define OP_GTE 5
#define OP_LTE 6
#define OP_CEQ 7
#define OP_INSIDE 8
#define OP_CL_BRAKET 10
/*
* boolean operators
*/
#define OP_AND_STR "AND"
#define OP_NOT_STR "NOT"
#define OP_OR_STR "OR"
#define OP_XOR_STR "XOR"
#define OP_AND 11
#define OP_NOT 12
#define OP_OR 13
#define OP_XOR 14
/*
* string operators
*/
#define OP_CAT_STR "+"
#define OP_CAT 15
typedef BYTE op_t;
/*
* forward references
*/
STRPTR eval_expression(HSCPRC * hp, HSCATTR * dest, STRPTR endstr);
/*
*
* global funcs
*
*/
/*
* err_op: unknown binary operator
*/
static VOID err_op(HSCPRC * hp, STRPTR opstr)
{
hsc_message(hp, MSG_UNKN_BINOP, "unknown binary operator %q", opstr);
}
/*
* eval_boolstr
*/
static BOOL eval_boolstr(STRPTR s)
{
if (s[0])
return (TRUE);
else
return (FALSE);
}
/* check for empty brakets (after GetTime/GetGmTime) */
static VOID check_brakets(HSCPRC * hp)
{
if (parse_wd(hp, "("))
parse_wd(hp, ")");
}
/*
* gettimestr
*/
static EXPSTR *gettimestr(HSCPRC * hp, struct tm *time)
{
#define TIMEBUF_INC 20
STRPTR timefmt = get_vartext_byname(hp->defattr, TIMEFORMAT_ATTR);
EXPSTR *timebuf = init_estr(TIMEBUF_INC);
BOOL strftrc = 0; /* result of strftime() */
size_t i; /* loop var */
/* set default time format */
if (!timefmt)
timefmt = "%d-%b-%Y, %H:%M";
while (!(hp->fatal) && !strftrc)
{
/* expand timebuffer */
for (i = 0; i < TIMEBUF_INC; i++)
app_estrch(timebuf, '.');
D(fprintf(stderr, DHL " timebuf: inc+%d\n", TIMEBUF_INC));
/* output time */
strftrc = strftime(estr2str(timebuf), estrlen(timebuf),
timefmt, time);
}
if (!strftrc)
{
del_estr(timebuf);
timebuf = NULL;
}
return (timebuf);
}
/*
* getfilesize
*
* get size of a specific file
*
* templates for HSC.FORMAT.FILESIZE:
* %b size in byte
* %k size in Kbyte
* %m size in MByte
* %g size in Gbyte
* %a size, unit computed automatically
* %u unit for %A (none, "K", "M" or "G")
*/
static STRPTR getfilesize(HSCPRC * hp, EXPSTR * dest, STRPTR uri)
{
STRPTR filesizestr = NULL;
FILE *file = NULL;
LONG filesize = 0; /* filesize in byte */
LONG filesize_k = 0; /* filesize in Kbyte */
LONG filesize_m = 0; /* filesize in Mbyte */
LONG filesize_g = 0; /* filesize in Gbyte */
LONG filesize_auto = 0; /* filesize in auto-units (%A) */
EXPSTR *efilename = init_estr(32);
STRPTR filename = NULL;
STRPTR sizeunit = "";
STRPTR s = get_vartext_byname(hp->defattr,
FILESIZEFORMAT_ATTR);
conv_hscuri2file(hp, efilename, uri);
filename = estr2str(efilename);
D(fprintf(stderr, DHL " GETFILESIZE(`%s')\n", filename));
errno = 0;
file = fopen(filename, "r");
if (file)
{
/* retrieve size */
fseek(file, 0L, SEEK_END);
filesize = ftell(file);
fclose(file);
/* compute size in units, */
filesize_k = (filesize + 512) >> 10;
filesize_m = (filesize_k + 512) >> 10;
filesize_g = (filesize_m + 512) >> 10;
/* compute auto-size */
if (filesize_g > 10)
{
filesize_auto = filesize_g;
sizeunit = "G";
}
else if (filesize_m > 10)
{
filesize_auto = filesize_m;
sizeunit = "M";
}
else if (filesize_k > 10)
{
filesize_auto = filesize_k;
sizeunit = "K";
}
else
{
filesize_auto = filesize;
sizeunit = "";
}
}
else
{
/* file not found */
filesize = 0;
filesize_k = 0;
filesize_m = 0;
filesize_g = 0;
filesize_auto = 0;
sizeunit = "";
hsc_msg_nouri(hp, filename, uri, "get filesize");
}
/* parse template */
clr_estr(dest);
if (s)
{
while (s[0])
{
if (s[0] == '%')
{
if (s[1])
s++;
switch (s[0])
{
case 'b':
app_estr(dest, long2str(filesize));
break;
case 'k':
app_estr(dest, long2str(filesize_k));
break;
case 'm':
app_estr(dest, long2str(filesize_m));
break;
case 'g':
app_estr(dest, long2str(filesize_g));
break;
case 'a':
app_estr(dest, long2str(filesize_auto));
break;
case 'u':
app_estr(dest, sizeunit);
break;
default:
app_estrch(dest, '%');
app_estrch(dest, s[0]);
break;
}
}
else
app_estrch(dest, s[0]);
s++;
}
}
else
{
D(panic("no template for filesize-format"));
}
/* set filesize-str */
filesizestr = estr2str(dest);
D(fprintf(stderr, DHL " =`%s'\n", filesizestr));
del_estr(efilename);
return (filesizestr);
}
/*
* check_attrname
*
* check string for legal attribute name
*/
BOOL check_attrname(HSCPRC * hp, STRPTR name)
{
BOOL ok = FALSE;
if (hsc_normch(name[0]))
ok = TRUE;
else
hsc_message(hp, MSG_ILLG_ATTRNAME,
"illegal attribute identifier %q", name);
return (ok);
}
/*
* eval_attrname
*
* read next word and check it for a legal
* attribute identifier
*/
static STRPTR eval_attrname(HSCPRC * hp)
{
STRPTR result = NULL;
STRPTR nw = infgetw(hp->inpf);
if (nw)
{
if (check_attrname(hp, nw))
result = nw;
}
else
hsc_msg_eof(hp, "attribute identifier expected");
return (result);
}
/*
* quotestr
*
* return readable string for quote-kind
*/
#define DOUBLE_QUOTE '\"'
#define SINGLE_QUOTE '\''
STRPTR quotestr(int quote)
{
STRPTR s = "UNKNOWN";
if (quote == '\"')
s = "[double]";
else if (quote == '\'')
s = "[single]";
else if (quote == VQ_NO_QUOTE)
s = "[none]";
else
panic("unknown quote-kind");
return (s);
}
/*
* choose_quote
*
* choose quote to be used for attr, depending on
* hp->quotemode and quotes used inside the value
*/
static VOID choose_quote(HSCPRC * hp, HSCATTR * attr)
{
int quote = attr->quote;
LONG qm = hp->quotemode; /* lazy.. */
BOOL single_quote = FALSE;
BOOL double_quote = FALSE;
BOOL nasty_char = FALSE;
STRPTR value = get_vartext(attr);
D(fprintf(stderr, DHL " choosing quote\n"));
/* scan attribute value for quotes */
while (value[0])
{
if (value[0] == SINGLE_QUOTE)
{
D(fprintf(stderr, DHL " single quote detected\n"));
single_quote = TRUE;
nasty_char = TRUE;
}
else if (value[0] == DOUBLE_QUOTE)
{
D(fprintf(stderr, DHL " double quote detected\n"));
double_quote = TRUE;
nasty_char = TRUE;
}
else if (!hsc_normch(value[0]) && !nasty_char)
{
D(fprintf(stderr, DHL " nasty-char #%d detected\n", value[0]));
nasty_char = TRUE;
}
value++;
}
if (qm == QMODE_KEEP)
{
#if 0 /* TODO: enable this */
/* check, if quote is missing */
if ((attr->quote == VQ_NO_QUOTE)
&& nasty_char)
{
hsc_message(hp, MSG_REQU_QUOTE,
"value for %A requires quotes", attr);
}
#endif
}
else
{
/* choose quote */
if (single_quote && double_quote)
{
/* both kind of quotes appeared in value:
* replace double-quotes by """ */
EXPSTR *newval = init_estr(32); /* new attribute value */
/* scan old value for `\"', replace them by `"'
* and store new value in newval */
value = get_vartext(attr);
while (value[0])
{
if (value[0] == DOUBLE_QUOTE)
{
D(fprintf(stderr, DHL " replace by `"' in value\n"));
/* TODO: message */
app_estr(newval, """);
}
else
app_estrch(newval, value[0]);
value++;
}
/* update attribute value */
set_vartext(attr, estr2str(newval));
quote = DOUBLE_QUOTE;
del_estr(newval);
}
else
{
if (single_quote)
{
D(fprintf(stderr, DHL " double quote forced\n"));
quote = DOUBLE_QUOTE;
}
else if (double_quote)
{
D(fprintf(stderr, DHL " single quote forced\n"));
quote = SINGLE_QUOTE;
}
else
{
/* no quote in value: choose quote user prefers */
if (qm == QMODE_SINGLE)
{
D(fprintf(stderr, DHL " single quote preferd\n"));
quote = SINGLE_QUOTE;
}
else if (qm == QMODE_DOUBLE)
{
D(fprintf(stderr, DHL " double quote prefered\n"));
quote = DOUBLE_QUOTE;
}
else if (qm == QMODE_NONE)
{
if (nasty_char)
{
D(fprintf(stderr, DHL " quote needed (nasty char)\n"));
quote = DOUBLE_QUOTE;
}
else
{
D(fprintf(stderr, DHL " no quote needed\n"));
quote = VQ_NO_QUOTE;
}
}
else
{
panic("illegal quote-mode");
}
}
}
/* check, if quote has changed */
if (attr->quote != quote)
{
hsc_message(hp, MSG_CHANGED_QUOTE,
"changed quotes for %A from %s to %s",
attr, quotestr(attr->quote), quotestr(quote));
}
}
attr->quote = quote;
}
/*
* try_eval_unary_op
*
* reads next word and tries to interpret it as an unary
* operator; if no fitting operator exists, return NULL,
* else immediatly process the operator and return its
* result
*/
static STRPTR try_eval_unary_op(HSCPRC * hp, HSCATTR * dest, BOOL * err)
{
STRPTR eval_result = NULL;
INFILE *inpf = hp->inpf;
STRPTR nw = eval_attrname(hp);
HSCATTR *tmpdest = new_hscattr(PREFIX_TMPATTR "unary.operator");
tmpdest->vartype = VT_STRING;
*err = FALSE;
if (nw)
{
if (!upstrcmp(nw, "NOT"))
{
/* TODO: this part looks a bit stupid... */
STRPTR nw = infgetw(inpf);
if (nw)
{
BOOL err_rec = FALSE; /* error var for recursive call */
STRPTR endstr = NULL;
if (strcmp(nw, "("))
{
/* try to process another unary operator */
inungetcw(inpf);
eval_result = try_eval_unary_op(hp, dest, &err_rec);
}
else
endstr = ")";
/* if not, process another expression */
if (!eval_result && !err_rec)
eval_result = eval_expression(hp, dest, endstr);
}
else
hsc_msg_eof(hp, "after NOT");
/* set result or return error */
if (eval_result)
{
set_varbool(dest, !get_varbool(dest));
eval_result = get_vartext(dest);
}
else
*err = TRUE;
}
else if (!upstrcmp(nw, "DEFINED"))
{
nw = eval_attrname(hp);
if (nw)
{
HSCATTR *attr = find_varname(hp->defattr, nw);
if (attr)
set_varbool(dest, TRUE);
else
set_varbool(dest, FALSE);
eval_result = get_vartext(dest);
}
}
else if (!upstrcmp(nw, "EXISTS"))
{
/* check existence of file */
eval_result = eval_expression(hp, tmpdest, NULL);
if (eval_result)
{
FILE *file = NULL;
EXPSTR *dest_fname = init_estr(64);
D(fprintf(stderr, DHL " EXISTS(`%s')\n", eval_result));
conv_hscuri2file(hp, dest_fname, eval_result);
file = fopen(eval_result, "r");
if (file)
{
fclose(file);
set_varbool(dest, TRUE);
}
else
set_varbool(dest, FALSE);
del_estr(dest_fname);
eval_result = get_vartext(dest);
}
}
else if (!upstrcmp(nw, "GETENV"))
{
/* get environment variable */
eval_result = eval_expression(hp, dest, NULL);
if (eval_result)
{
STRPTR env_value = getenv(get_vartext(dest));
D(fprintf(stderr, DHL " GETENV(`%s')\n", eval_result));
if (!env_value)
{
hsc_message(hp, MSG_UNKN_ENVVAR,
"unknown environment variable %q",
get_vartext(dest));
env_value = "";
}
set_vartext(dest, env_value);
eval_result = get_vartext(dest);
D(fprintf(stderr, DHL " =`%s'\n", eval_result));
}
}
else if (!upstrcmp(nw, "GETFILESIZE"))
{
/* retrieve size of a file */
EXPSTR *filesizestr = init_estr(0);
HSCATTR *filedestattr = new_hscattr(PREFIX_TMPATTR "get.filesize");
STRPTR filename = NULL;
eval_result = NULL;
filedestattr->vartype = VT_STRING;
filename = eval_expression(hp, filedestattr, NULL);
if (filename)
{
eval_result = getfilesize(hp, filesizestr, filename);
}
if (eval_result)
{
set_vartext(dest, eval_result);
eval_result = get_vartext(dest);
}
del_hscattr(filedestattr);
del_estr(filesizestr);
}
else if (!upstrcmp(nw, "GETTIME"))
{
/* get local time */
EXPSTR *timestr = gettimestr(hp, localtime(&(hp->start_time)));
D(fprintf(stderr, DHL " GETTIME\n"));
if (timestr)
{
set_vartext(dest, estr2str(timestr));
del_estr(timestr);
eval_result = get_vartext(dest);
}
check_brakets(hp);
}
else if (!upstrcmp(nw, "GETGMTIME"))
{
/* get greenwich mean time */
EXPSTR *timestr = gettimestr(hp, gmtime(&(hp->start_time)));
D(fprintf(stderr, DHL " GETGMTIME\n"));
if (timestr)
{
set_vartext(dest, estr2str(timestr));
del_estr(timestr);
eval_result = get_vartext(dest);
}
check_brakets(hp);
}
else if (!upstrcmp(nw, "SET"))
{
nw = eval_attrname(hp);
if (nw)
{
HSCATTR *attr = find_varname(hp->defattr, nw);
if (attr)
{
if (attr->vartype == VT_BOOL)
{
set_varbool(dest, get_varbool(attr));
}
else if (get_vartext(attr))
set_varbool(dest, TRUE);
else
set_varbool(dest, FALSE);
eval_result = get_vartext(dest);
}
else
{
hsc_msg_unkn_attr(hp, nw);
*err = TRUE;
}
}
}
else
inungetcw(inpf);
}
del_hscattr(tmpdest);
if (!nw)
*err = TRUE;
return (eval_result);
}
/*
* eval_op
*
* evaluate binary operator string
*/
static BYTE eval_op(HSCPRC * hp)
{
BYTE op = OP_NONE;
BOOL op_eof = FALSE; /* flag: end of file reached */
INFILE *inpf = hp->inpf;
STRPTR nw = infgetw(inpf);
D(fprintf(stderr, DHL " operator \"%s", nw));
if (nw)
{
/* boolean operators */
if (!upstrcmp(nw, OP_AND_STR))
op = OP_AND;
else if (!upstrcmp(nw, OP_OR_STR))
op = OP_OR;
else if (!upstrcmp(nw, OP_XOR_STR))
op = OP_XOR;
/* concatenation operator */
else if (!strcmp(nw, OP_CAT_STR))
op = OP_CAT;
/* closing braket */
else if (!strcmp(nw, OP_CL_BRAKET_STR))
op = OP_CL_BRAKET;
/* comparison operators */
else if (strenum(nw, "<|=|>", '|', STEN_CASE))
{
STRARR opstr[3];
int ch;
/* determine whole comparison operator:
* take first word, and check for next
* single character, if it is one of
* "<", "=" or ">", too. if so, append
* it to the string that tells the
* operator.
*/
strcpy(opstr, nw);
ch = infgetc(inpf);
if (ch != EOF)
{
D(fprintf(stderr, "%c", (char) ch));
if (strchr("<=>", ch))
{
opstr[1] = ch;
opstr[2] = 0;
}
else
inungetc(ch, inpf);
}
else
op_eof = TRUE;
/* find out comparison operator */
if (!strcmp(nw, OP_EQ_STR))
op = OP_EQ;
else if (!strcmp(nw, OP_NEQ_STR))
op = OP_EQ;
else if (!strcmp(nw, OP_GT_STR))
op = OP_GT;
else if (!strcmp(nw, OP_LT_STR))
op = OP_LT;
else if (!strcmp(nw, OP_LTE_STR))
op = OP_LTE;
else if (!strcmp(nw, OP_GTE_STR))
op = OP_GTE;
else if (!strcmp(nw, OP_CEQ_STR))
op = OP_CEQ;
else
err_op(hp, opstr);
}
else
err_op(hp, nw);
}
else
op_eof = TRUE;
D(fprintf(stderr, "\"\n"));
if (op_eof)
hsc_msg_eof(hp, "operator expected");
return (op);
}
/*
* process_op
*/
static VOID process_op(HSCPRC * hp, HSCATTR * dest, BYTE op, STRPTR str1, STRPTR str2)
{
EXPSTR *result = init_estr(40);
BOOL result_set = FALSE;
D(fprintf(stderr, DHL " \"%s\", \"%s\"\n", str1, str2));
if (str2 && (op != OP_NONE))
{
BOOL bool_val1 = eval_boolstr(str1);
BOOL bool_val2 = eval_boolstr(str2);
switch (op)
{
case OP_AND:
if (bool_val1 && bool_val2)
set_varbool(dest, TRUE);
else
set_varbool(dest, FALSE);
break;
case OP_OR:
if (bool_val1 || bool_val2)
set_varbool(dest, TRUE);
else
set_varbool(dest, FALSE);
break;
case OP_XOR:
if ((bool_val1 || bool_val2)
&& !(bool_val1 && bool_val2)
)
set_varbool(dest, TRUE);
else
set_varbool(dest, FALSE);
break;
case OP_EQ:
/* string comparison, ignore case */
if (!upstrcmp(str1, str2))
set_varbool(dest, TRUE);
else
set_varbool(dest, FALSE);
break;
case OP_NEQ:
/* string comparison "<>" */
if (upstrcmp(str1, str2))
set_varbool(dest, TRUE);
else
set_varbool(dest, FALSE);
break;
case OP_GT:
/* string comparison ">" */
if (upstrcmp(str1, str2) > 0)
set_varbool(dest, TRUE);
else
set_varbool(dest, FALSE);
break;
case OP_LT:
/* string comparison "<" */
if (upstrcmp(str1, str2) < 0)
set_varbool(dest, TRUE);
else
set_varbool(dest, FALSE);
break;
case OP_GTE:
/* string comparison ">=" */
if (upstrcmp(str1, str2) >= 0)
set_varbool(dest, TRUE);
else
set_varbool(dest, FALSE);
break;
case OP_LTE:
/* string comparison "<=" */
if (upstrcmp(str1, str2) <= 0)
set_varbool(dest, TRUE);
else
set_varbool(dest, FALSE);
break;
case OP_CEQ:
/* string comparison, case sensitive */
if (!strcmp(str1, str2))
set_varbool(dest, TRUE);
else
set_varbool(dest, FALSE);
break;
case OP_CAT:
/* concat two expressions */
set_estr(result, str1);
app_estr(result, str2);
result_set = TRUE;
break;
default:
panic("empty operator");
break;
}
}
/* store result in destination attribute,
* if this has not happened yet
*/
if (result_set)
set_vartext(dest, estr2str(result));
/* remove temp. string for result */
del_estr(result);
}
/*
*-------------------------------------
* eval_expression: evaluate expression
*-------------------------------------
*/
/*
* eval_string_expr
*
* evaluate string expression WITH enclosing quotes
*/
static STRPTR eval_string_expr(HSCPRC * hp, HSCATTR * dest)
{
INFILE *inpf = hp->inpf;
STRPTR eval_result = NULL;
EXPSTR *tmpstr = init_estr(TMP_STEPSIZE);
int quote;
/* get quote char */
quote = infgetc(inpf);
if (quote != EOF)
{
BOOL end = FALSE;
while (!end)
{
int ch = infgetc(inpf);
if (ch == EOF)
{
hsc_msg_eof(hp, "reading string constant");
eval_result = NULL;
end = TRUE;
}
else if (ch != quote)
{
/* check for LF inside string */
if (ch == '\n')
hsc_message(hp, MSG_STR_LF,
"linefeed found inside string");
/* append next char to string */
app_estrch(tmpstr, ch);
}
else
{
/* closing quote reached */
eval_result = estr2str(tmpstr);
end = TRUE;
}
}
}
else
hsc_msg_eof(hp, "reading string constant");
/* set new attribute value */
if (eval_result)
{
/* set new quotes */
dest->quote = quote;
/* set new value */
set_vartext(dest, eval_result);
eval_result = get_vartext(dest);
}
/* remove temp. string */
del_estr(tmpstr);
return (eval_result);
}
/*
* eval_string_expr_noquote
*
* evaluate string expression WITHOUT enclosing quotes
*/
STRPTR eval_string_expr_noquote(HSCPRC * hp, HSCATTR * dest)
{
/* TODO: check for ch==">": attrval missing */
INFILE *inpf = hp->inpf;
STRPTR eval_result = NULL;
EXPSTR *tmpstr = init_estr(TMP_STEPSIZE);
BOOL end = FALSE;
/* TODO: check for empty expression */
/*
* read next char from input file until a
* closing quote if found.
* if the arg had no quote, a white space
* or a '>' is used to detect end of arg.
* if a LF is found, view error message
*/
while (!end)
{
int ch = infgetc(inpf);
if (ch == EOF)
{
hsc_msg_eof(hp, "reading attribute");
end = TRUE;
}
else if ((ch == '\n')
|| (inf_isws(ch, inpf) || (ch == '>')))
{
/* end of arg reached */
inungetc(ch, inpf);
eval_result = estr2str(tmpstr);
end = TRUE;
}
else
{
/* append next char to tmpstr */
app_estrch(tmpstr, ch);
}
}
/* set new attribute value */
if (eval_result)
{
set_vartext(dest, eval_result);
eval_result = get_vartext(dest);
}
/* remove temp. string */
del_estr(tmpstr);
return (eval_result);
}
/*
* eval_attrref
*
* evaluate reference to attribute
*
*/
static STRPTR eval_attrref(HSCPRC * hp, HSCATTR * destattr)
{
STRPTR eval_result = NULL;
STRPTR nw = eval_attrname(hp);
if (nw)
{
HSCATTR *refvar = find_varname(hp->defattr, nw);
if (refvar)
{
/* TODO: type checking */
destattr->quote = refvar->quote;
eval_result = refvar->text;
/* check empty/circular reference */
if (!eval_result)
hsc_message(hp, MSG_EMPTY_SYMB_REF,
"empty reference to %A", destattr);
/* debugging message */
DDA(fprintf(stderr, DHL " %s refers to (%s)\n",
destattr->name, refvar->name));
}
else
{
/* reference to unknown destattr */
hsc_msg_unkn_attr(hp, nw);
}
/* set empty value for reference to NULL */
if ((!refvar) || (!eval_result))
{
/* return empty destattr */
destattr->quote = '"';
eval_result = "";
}
}
/* set value of destination attribute */
if (eval_result)
set_vartext(destattr, eval_result);
return (eval_result);
}
/*
* eval_expression
*
* params: dest....attribute where to store result in
* inpf....input file
* err.....flag that is set to TRUE if an error occured
* endstr..word that is expected at end of expession;
* NULL for no special ending word
* result: result of evaluation (IF_TRUE or FALSE)
*
* NOTE: if endstr==NULL, that means that eval_expression() is called
* immediatly after the "=" of an attribute. In this case, if no
* quotes are found as next char, all chars are read until the next
* white-space or LF occures.
* If no special char was found until now (only "A".."Z", "_", "-" and
* digits occured), we first interpret the string as name for an
* attribute reference; if such an attribute does not exist, it is
* asumed that the value passed is a string constant (same as it would
* have been enclosed in quotes).
*
*/
STRPTR eval_expression(HSCPRC * hp, HSCATTR * dest, STRPTR endstr)
{
/* TODO: endstr needs to be boolean flag only */
INFILE *inpf = hp->inpf;
EXPSTR *vararg = init_estr(TMP_STEPSIZE);
/* used as destination by eval_string_exprXX() */
STRPTR exprstr = NULL; /* return value */
int ch; /* char read from input */
/* skip white spaces */
infskip_ws(inpf);
/* read dest->quote char */
ch = infgetc(inpf);
if (!strchr(VQ_STR_QUOTE, ch))
if (ch != EOF)
dest->quote = VQ_NO_QUOTE;
else
hsc_msg_eof(hp, "reading attribute");
else
dest->quote = ch;
/* skip linefeeds, if evaluation hsc-expression */
if (endstr)
skip_lfs(hp);
if (ch == '(')
{
/* process braket */
exprstr = eval_expression(hp, dest, ")");
/* set generic double quote */
if (!endstr)
dest->quote = '\"';
}
else if (ch != EOF)
{
/* write current char read back to input buffer */
inungetc(ch, inpf);
if (dest->quote != VQ_NO_QUOTE)
{
/* process string expression with quotes */
exprstr = eval_string_expr(hp, dest);
}
else if (endstr)
{
BOOL err = FALSE;
/* try to process unary operator */
exprstr = try_eval_unary_op(hp, dest, &err);
/* process attribute reference */
if (!exprstr && !err)
exprstr = eval_attrref(hp, dest);
}
else
{
/* process string expression without quotes */
exprstr = eval_string_expr_noquote(hp, dest);
}
}
if (exprstr && endstr)
{
BYTE op;
skip_lfs(hp); /* skip linefeeds */
/* evaluate operator */
op = eval_op(hp);
if (op == OP_CL_BRAKET)
DMSG(" END mark operator reached");
else if (op != OP_NONE)
{
/* no endmark reached */
STRPTR str1 = exprstr;
/* read second operator */
if (op != OP_NONE)
{
STRPTR str2 = NULL;
HSCATTR *dest1 = new_hscattr(PREFIX_TMPATTR "2nd.operand");
/* init dummy attribute */
dest1->vartype = dest->vartype;
dest1->quote = dest->quote;
/* compute second value */
str2 = eval_expression(hp, dest1, endstr);
if (str2)
process_op(hp, dest, op, str1, str2);
else
exprstr = NULL;
/* remove result of second value */
del_hscattr((APTR) dest1);
}
else
{
/* TODO: skip expression until ">" */
exprstr = NULL;
}
if (exprstr)
{
/* store result */
exprstr = get_vartext(dest);
}
}
else
{
DMSG(" NO operator");
}
}
if (!endstr)
{
if (exprstr && !endstr)
{
/*
* set quote, depending on quotemode
*/
#if 0 /* TODO:remove */
switch (hp->quotemode)
{
case QMODE_KEEP:
/* do nufin */
break;
case QMODE_DOUBLE:
dest->quote = '\"';
break;
case QMODE_SINGLE:
dest->quote = '\'';
break;
case QMODE_NONE:
dest->quote = VQ_NO_QUOTE;
break;
default:
panic("unknown quotemode");
break;
}
#else
if ((dest->vartype != VT_BOOL)
&& !(dest->varflag & (VF_MACRO | VF_KEEP_QUOTES)))
{
choose_quote(hp, dest);
}
#endif
/*
* check enum type
*/
if (dest->vartype == VT_ENUM)
{
if (!strenum(exprstr, dest->enumstr, '|', STEN_NOCASE))
{
/* unknown enum value */
hsc_message(hp, MSG_ENUM_UNKN,
"unknown value %q for enumerator %A",
exprstr, dest);
}
}
/*
* check color value
*/
else if (dest->vartype == VT_COLOR)
{
BOOL ok = FALSE;
size_t color_len = strlen("#rrggbb");
if (exprstr[0] == '#')
{
/* check RGB-value */
if (strlen(exprstr) == color_len)
{
size_t i = 1;
ok = TRUE;
for (; i < color_len; i++)
if (!isxdigit(exprstr[i]))
ok = FALSE;
}
}
else
{
/* check color name */
if (hp->color_names)
{
if (strenum(exprstr, hp->color_names, '|', STEN_NOCASE))
ok = TRUE;
}
else
ok = TRUE;
}
if (!ok)
/* illegal color value */
hsc_message(hp, MSG_ILLG_COLOR,
"illegal color value %q for %A",
exprstr, dest);
}
/*
* check numeric value
*/
else if (dest->vartype == VT_NUM)
{
BOOL ok = FALSE;
int i = 0;
if ((exprstr[0] == '+')
|| (exprstr[0] == '-'))
{
i = 1;
}
if (strlen(exprstr) - i)
{
ok = TRUE;
while (exprstr[i] && ok)
{
if (!isdigit(exprstr[i]))
ok = FALSE;
else
i++;
}
}
if (!ok)
/* unknown enum value */
hsc_message(hp, MSG_ILLG_NUM,
"illegal numeric value %q for %A",
exprstr, dest);
}
/*
* for boolean attributes, set the name
* of the attribute if TRUE, or set an
* empty string, if FALSE
*/
else if (dest->vartype == VT_BOOL)
if (eval_boolstr(exprstr))
set_vartext(dest, dest->name);
else
set_vartext(dest, "");
/*
* checks performed only for tags,
* but are skipped for macros
*/
if (!(dest->varflag & VF_MACRO))
{
/*
* parse uri (convert abs.uris, check existence)
*/
if (dest->vartype == VT_URI)
{
EXPSTR *dest_uri = init_estr(32);
parse_uri(hp, dest_uri, exprstr);
set_vartext(dest, estr2str(dest_uri));
del_estr(dest_uri);
}
}
exprstr = get_vartext(dest);
}
else
{
/* if error occured,
* skip until ">", unread ">"
*/
skip_until_eot(hp, NULL);
if (!hp->fatal)
inungetcw(inpf);
}
}
del_estr(vararg);
return (exprstr);
}
/*
* eval_cloneattr
*
* read name of attribute, check if it has been set;
* if so, return value of attribute.
* all possible errors are handled by this function.
*
* params: hp.....hsc-process
* dest...detination attribute where to store value
* result: value of attribute, if it has been set, or NULL
* if attribute is empty or unknown or other error
* has occured.
*/
STRPTR eval_cloneattr(HSCPRC * hp, HSCATTR *dest)
{
STRPTR nw = eval_attrname(hp);
STRPTR attrval = NULL;
if (nw)
{
HSCATTR *attr = find_varname(hp->defattr, nw);
if (attr)
{
attrval = get_vartext(attr);
dest->quote = attr->quote;
}
else
hsc_msg_unkn_attr(hp, nw);
}
/* update attribute value and quotes */
if (attrval)
{
set_vartext(dest, attrval);
attrval = get_vartext(dest);
choose_quote(hp, dest);
}
return( attrval);
}